﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace FUSE
{
    public class Map
    {
        //grid to contain all galaxy components and current position of the ship
        public Hashtable galaxyComponentsTable;    //isn't this supposed to be a hashtable
        //the gravitational forces of the planets
        public GenericForce[,] galaxyForces;

        private Rectangle DEFAULT_BG_RECTANGLE = new Rectangle(0, 0, 1, 1);
        private Texture2D backgroundTex;
        private Rectangle backgroundRectangle;

        private Rectangle source;

        public Texture2D visualForcesTex;
        //TODO: recalculate this
        public float maxAbsForce =100;

        private int xSize;
        private int ySize;


        private Vector2 screenPosition;
        private Vector2 DEFAULT_SCREEN_POS = new Vector2(-1, -1);

        private Vector2 DEFAULT_SCALE = Vector2.One;
        private Vector2 scale;

        public MapType currMapType;
        public MapGenerator.Difficulty mapDifficulty;

        public float[,] absoluteForceMap;
        public int[,] colorMap;

        public Boolean visualization = false;
        public Boolean hasPaidForVisualization = false;

        public enum MapType
        {
            Tutorial = 1,
            Survival
        }


        public Map()
        {
            this.xSize = 1;
            this.ySize = 1;

            this.screenPosition = DEFAULT_SCREEN_POS;
            this.scale = DEFAULT_SCALE;

            this.backgroundRectangle = DEFAULT_BG_RECTANGLE;

            galaxyComponentsTable = new Hashtable();
            galaxyForces = new GenericForce[xSize, ySize];

        }

        public Map(int gotXsize, int gotYsize)
        {
            this.xSize = gotXsize;
            this.ySize = gotYsize;

            this.screenPosition = DEFAULT_SCREEN_POS;
            this.scale = DEFAULT_SCALE;

            this.backgroundRectangle = new Rectangle(0, 0, xSize, ySize);
            this.source = backgroundRectangle;

            galaxyComponentsTable = new Hashtable();
            galaxyForces = new GenericForce[xSize,ySize];
        }

        public Map(Texture2D backgroundTexture)
        {
            this.backgroundTex = backgroundTexture;
            this.xSize = backgroundTexture.Width;
            this.ySize = backgroundTexture.Height;

            this.screenPosition = DEFAULT_SCREEN_POS;
            this.scale = DEFAULT_SCALE;

            this.backgroundRectangle = new Rectangle(0, 0, xSize, ySize);
            this.source = backgroundRectangle;

            galaxyComponentsTable = new Hashtable();
            galaxyForces = new GenericForce[xSize, ySize];
        }

        public Map(Texture2D backgroundTexture, int mapWidth, int mapHeight)
        {
            this.backgroundTex = backgroundTexture;
            this.xSize = mapWidth;
            this.ySize = mapHeight;

            this.screenPosition = DEFAULT_SCREEN_POS;

            this.scale.X = Math.Abs(backgroundTexture.Width / mapWidth);
            this.scale.Y = Math.Abs(backgroundTexture.Height / mapHeight);

            this.backgroundRectangle = new Rectangle(0, 0, backgroundTexture.Width, backgroundTexture.Height);
            this.source = new Rectangle(0, 0, backgroundTex.Width, backgroundTex.Height);

            galaxyComponentsTable = new Hashtable();
            galaxyForces = new GenericForce[xSize, ySize];
        }

        public int getXSize()
        {
            return xSize;
        }

        public int getYSize()
        {
            return ySize;
        }

        public override string ToString()
        {
            
            String output = String.Empty;
            output += "Planet locations" + "\n";
            foreach (DictionaryEntry item in galaxyComponentsTable)
            {
                output += "[" + ((GalaxyComponent)item.Value).RenderPosition.X + "," + 
                    ((GalaxyComponent)item.Value).RenderPosition.Y + "] ";
            }
            output += "\nForces\n";
            foreach (GenericForce force in galaxyForces)
            {
                output += "[" + force.Force.X + force.Force.Y + "] ";
            }
            
            output += "\nEnd map\n";

            return output;
        }

        public Texture2D BackgroundTexture
        {
            get { return backgroundTex; }
            set { backgroundTex = value; }
        }

        public void Update(GameTime gameTime, Viewport viewport, Vector2 shipPosition)
        {
            int initialScreenYPos = (this.galaxyForces.GetLength(1) - viewport.Height);

            if (screenPosition == DEFAULT_SCREEN_POS)
            {
                screenPosition = new Vector2(0, initialScreenYPos);
            }
            else if (shipPosition.Y < (initialScreenYPos + (viewport.Height / 2))
                && shipPosition.Y > (viewport.Height / 2))
            {
                screenPosition = new Vector2(0, (shipPosition.Y - (viewport.Height / 2)));
            }
            else if (shipPosition.Y > (initialScreenYPos + (viewport.Height / 2)))
            {
                screenPosition = new Vector2(0, initialScreenYPos);
            }
            else if (shipPosition.Y < (viewport.Height / 2))
            {
                screenPosition = Vector2.Zero;
            }
            
            double rescaledWidth = (double)(viewport.Width / backgroundTex.Width);
            double rescaledHeight = (double)(viewport.Height / rescaledWidth);
            
            source.Height = (int)rescaledHeight;
            source.Width = backgroundTex.Width;

            Vector2 initialSourcePos = new Vector2(0, backgroundTex.Height - source.Height);

            //double initialSourcePercent = (initialSourcePos.Y + (source.Height / 2)) / this.ySize;
            double shipMovementPercent = shipPosition.Y / this.ySize;

            //double mapPercent = this.ySize * 0.01;

            //double percentIncrement = initialSourcePos.Y * 0.1;

            source.X = 0;
            source.Y = (int)(initialSourcePos.Y * shipMovementPercent);

            this.backgroundRectangle.Height = 600;
            this.backgroundRectangle.Width = viewport.Width;
        }

        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            //spriteBatch.Draw(backgroundTex, backgroundRectangle, Color.White);
            //overlay if visualization is true
            if (visualization == true)
            {
                spriteBatch.Draw(visualForcesTex, Vector2.Zero, Color.White);
            }
            foreach (DictionaryEntry item in galaxyComponentsTable)
            {
                ((GalaxyComponent)item.Value).Draw(spriteBatch, gameTime);
            }
        }

        public Vector2 ScreenPosition
        {
            get { return screenPosition; }
            set { this.screenPosition = value; }
        }

        public Rectangle BackgroundBounds
        {
            get { return backgroundRectangle; }
        }

        public Rectangle SourceBox
        {
            get { return source; }
        }
    }
}
